From f8f391ceb9a5178f0ffe55f059721a7747567020 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 25 Apr 2020 21:16:02 -0400 Subject: [PATCH] gtk-demo: Polish the clipboard demo The DND part of this demo was broken by recent icon theme changes. Make it work again. And make the demo nicer by breaking out a DemoImage widget. --- demos/gtk-demo/clipboard.c | 206 +----------------------- demos/gtk-demo/demo.gresource.xml | 4 + demos/gtk-demo/demoimage.c | 259 ++++++++++++++++++++++++++++++ demos/gtk-demo/demoimage.h | 13 ++ demos/gtk-demo/meson.build | 1 + 5 files changed, 283 insertions(+), 200 deletions(-) create mode 100644 demos/gtk-demo/demoimage.c create mode 100644 demos/gtk-demo/demoimage.h diff --git a/demos/gtk-demo/clipboard.c b/demos/gtk-demo/clipboard.c index 8fc6bb7cf5..ca8ca07670 100644 --- a/demos/gtk-demo/clipboard.c +++ b/demos/gtk-demo/clipboard.c @@ -12,6 +12,7 @@ #include #include #include +#include "demoimage.h" static GtkWidget *window = NULL; @@ -93,147 +94,6 @@ paste_button_clicked (GtkWidget *button, gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry); } -static GdkPaintable * -get_image_paintable (GtkImage *image) -{ - const gchar *icon_name; - GtkIconTheme *icon_theme; - GtkIconPaintable *icon; - - switch (gtk_image_get_storage_type (image)) - { - case GTK_IMAGE_PAINTABLE: - return g_object_ref (gtk_image_get_paintable (image)); - case GTK_IMAGE_ICON_NAME: - icon_name = gtk_image_get_icon_name (image); - icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image))); - icon = gtk_icon_theme_lookup_icon (icon_theme, - icon_name, - NULL, - 48, 1, - gtk_widget_get_direction (GTK_WIDGET (image)), - 0); - if (icon == NULL) - return NULL; - return GDK_PAINTABLE (icon); - - case GTK_IMAGE_EMPTY: - case GTK_IMAGE_GICON: - default: - g_warning ("Image storage type %d not handled", - gtk_image_get_storage_type (image)); - return NULL; - } -} - -static void -drag_begin (GtkDragSource *source, - GdkDrag *drag, - GtkWidget *widget) -{ - GdkPaintable *paintable; - - paintable = get_image_paintable (GTK_IMAGE (widget)); - if (paintable) - { - gtk_drag_source_set_icon (source, paintable, -2, -2); - g_object_unref (paintable); - } -} - -static GdkContentProvider * -prepare_drag (GtkDragSource *source, - double x, - double y, - GtkWidget *image) -{ - GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (image)); - - if (!GDK_IS_TEXTURE (paintable)) - return NULL; - - return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable); -} - -static gboolean -drag_drop (GtkDropTarget *dest, - const GValue *value, - double x, - double y, - GtkImage *image) -{ - GdkTexture *texture = g_value_get_object (value); - gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture)); - - return TRUE; -} - -static void -copy_image (GSimpleAction *action, - GVariant *value, - gpointer data) -{ - GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data)); - GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data)); - - if (GDK_IS_TEXTURE (paintable)) - gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable)); - - if (paintable) - g_object_unref (paintable); -} - -static void -paste_image_received (GObject *source, - GAsyncResult *result, - gpointer data) -{ - GdkTexture *texture; - - texture = gdk_clipboard_read_texture_finish (GDK_CLIPBOARD (source), result, NULL); - if (texture == NULL) - return; - - gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture)); - g_object_unref (texture); -} - -static void -paste_image (GSimpleAction *action, - GVariant *value, - gpointer data) -{ - GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data)); - gdk_clipboard_read_texture_async (clipboard, NULL, paste_image_received, data); -} - -static void -pressed_cb (GtkGesture *gesture, - int n_press, - double x, - double y, - GtkWidget *image) -{ - GtkWidget *popover; - GMenu *menu; - GMenuItem *item; - - menu = g_menu_new (); - item = g_menu_item_new (_("_Copy"), "clipboard.copy"); - g_menu_append_item (menu, item); - - item = g_menu_item_new (_("_Paste"), "clipboard.paste"); - g_menu_append_item (menu, item); - - popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu)); - gtk_widget_set_parent (popover, image); - - gtk_popover_set_pointing_to (GTK_POPOVER (popover), &(GdkRectangle) { x, y, 1, 1}); - gtk_popover_popup (GTK_POPOVER (popover)); - - g_object_unref (menu); -} - GtkWidget * do_clipboard (GtkWidget *do_widget) { @@ -243,14 +103,6 @@ do_clipboard (GtkWidget *do_widget) GtkWidget *label; GtkWidget *entry, *button; GtkWidget *image; - GtkGesture *gesture; - GActionEntry entries[] = { - { "copy", copy_image, NULL, NULL, NULL }, - { "paste", paste_image, NULL, NULL, NULL }, - }; - GActionGroup *actions; - GtkDragSource *source; - GtkDropTarget *dest; window = gtk_window_new (); gtk_window_set_display (GTK_WINDOW (window), @@ -320,62 +172,16 @@ do_clipboard (GtkWidget *do_widget) gtk_container_add (GTK_CONTAINER (vbox), hbox); /* Create the first image */ - image = gtk_image_new_from_icon_name ("dialog-warning"); - gtk_image_set_pixel_size (GTK_IMAGE (image), 48); + image = demo_image_new ("dialog-warning"); gtk_container_add (GTK_CONTAINER (hbox), image); - /* make image a drag source */ - source = gtk_drag_source_new (); - g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL); - g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source)); - - /* accept drops on image */ - dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY); - g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest)); - - /* context menu on image */ - gesture = gtk_gesture_click_new (); - gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY); - g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture)); - - actions = G_ACTION_GROUP (g_simple_action_group_new ()); - g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), image); - - gtk_widget_insert_action_group (image, "clipboard", actions); - - g_object_unref (actions); - /* Create the second image */ - image = gtk_image_new_from_icon_name ("process-stop"); - gtk_image_set_pixel_size (GTK_IMAGE (image), 48); + image = demo_image_new ("process-stop"); gtk_container_add (GTK_CONTAINER (hbox), image); - /* make image a drag source */ - source = gtk_drag_source_new (); - g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL); - g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source)); - - /* accept drops on image */ - dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY); - g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest)); - - /* context menu on image */ - gesture = gtk_gesture_click_new (); - gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY); - g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image); - gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture)); - - actions = G_ACTION_GROUP (g_simple_action_group_new ()); - g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), image); - - gtk_widget_insert_action_group (image, "clipboard", actions); - - g_object_unref (actions); + /* Create the third image */ + image = demo_image_new ("weather-clear"); + gtk_container_add (GTK_CONTAINER (hbox), image); } if (!gtk_widget_get_visible (window)) diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 3afc75c7db..6df9f252a1 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -12,6 +12,10 @@ demo.ui + + demoimage.c + demoimage.h + css_accordion.css reset.css diff --git a/demos/gtk-demo/demoimage.c b/demos/gtk-demo/demoimage.c new file mode 100644 index 0000000000..37c0acd684 --- /dev/null +++ b/demos/gtk-demo/demoimage.c @@ -0,0 +1,259 @@ +#include "demoimage.h" +#include + +struct _DemoImage { + GtkWidget parent_instance; + + GtkWidget *image; + GtkWidget *popover; +}; + +enum { + PROP_ICON_NAME = 1 +}; + +G_DEFINE_TYPE(DemoImage, demo_image, GTK_TYPE_WIDGET) + +static GdkPaintable * +get_image_paintable (GtkImage *image) +{ + const gchar *icon_name; + GtkIconTheme *icon_theme; + GtkIconPaintable *icon; + + switch (gtk_image_get_storage_type (image)) + { + case GTK_IMAGE_PAINTABLE: + return g_object_ref (gtk_image_get_paintable (image)); + case GTK_IMAGE_ICON_NAME: + icon_name = gtk_image_get_icon_name (image); + icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image))); + icon = gtk_icon_theme_lookup_icon (icon_theme, + icon_name, + NULL, + 48, 1, + gtk_widget_get_direction (GTK_WIDGET (image)), + 0); + if (icon == NULL) + return NULL; + return GDK_PAINTABLE (icon); + + case GTK_IMAGE_EMPTY: + case GTK_IMAGE_GICON: + default: + g_warning ("Image storage type %d not handled", + gtk_image_get_storage_type (image)); + return NULL; + } +} + +static void +drag_begin (GtkDragSource *source, + GdkDrag *drag, + gpointer data) +{ + GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source)); + DemoImage *demo = DEMO_IMAGE (widget); + GdkPaintable *paintable; + + paintable = get_image_paintable (GTK_IMAGE (demo->image)); + if (paintable) + { + gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2); + g_object_unref (paintable); + } +} + +static GdkContentProvider * +prepare_drag (GtkDragSource *source, + double x, + double y, + gpointer data) +{ + GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source)); + DemoImage *demo = DEMO_IMAGE (widget); + GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image)); + + return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable); +} + +static gboolean +drag_drop (GtkDropTarget *dest, + const GValue *value, + double x, + double y, + gpointer data) +{ + GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)); + DemoImage *demo = DEMO_IMAGE (widget); + GdkPaintable *paintable = g_value_get_object (value); + + gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable); + + return TRUE; +} + +static void +copy_image (GtkWidget *widget, + const char *action_name, + GVariant *parameter) +{ + GdkClipboard *clipboard = gtk_widget_get_clipboard (widget); + DemoImage *demo = DEMO_IMAGE (widget); + GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image)); + GValue value = G_VALUE_INIT; + + g_value_init (&value, GDK_TYPE_PAINTABLE); + g_value_set_object (&value, paintable); + gdk_clipboard_set_value (clipboard, &value); + g_value_unset (&value); + + if (paintable) + g_object_unref (paintable); +} + +static void +paste_image (GtkWidget *widget, + const char *action_name, + GVariant *parameter) +{ + GdkClipboard *clipboard = gtk_widget_get_clipboard (widget); + DemoImage *demo = DEMO_IMAGE (widget); + GdkContentProvider *content = gdk_clipboard_get_content (clipboard); + GValue value = G_VALUE_INIT; + GdkPaintable *paintable; + + g_value_init (&value, GDK_TYPE_PAINTABLE); + if (!gdk_content_provider_get_value (content, &value, NULL)) + return; + + paintable = GDK_PAINTABLE (g_value_get_object (&value)); + gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable); + g_value_unset (&value); +} + +static void +pressed_cb (GtkGesture *gesture, + int n_press, + double x, + double y, + gpointer data) +{ + DemoImage *demo = DEMO_IMAGE (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture))); + + gtk_popover_popup (GTK_POPOVER (demo->popover)); +} + +static void +demo_image_init (DemoImage *demo) +{ + GMenu *menu; + GMenuItem *item; + GtkDragSource *source; + GtkDropTarget *dest; + GtkGesture *gesture; + + demo->image = gtk_image_new (); + gtk_image_set_pixel_size (GTK_IMAGE (demo->image), 48); + gtk_widget_set_parent (demo->image, GTK_WIDGET (demo)); + + menu = g_menu_new (); + item = g_menu_item_new (_("_Copy"), "clipboard.copy"); + g_menu_append_item (menu, item); + + item = g_menu_item_new (_("_Paste"), "clipboard.paste"); + g_menu_append_item (menu, item); + + demo->popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu)); + gtk_widget_set_parent (demo->popover, GTK_WIDGET (demo)); + + source = gtk_drag_source_new (); + g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL); + g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL); + gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (source)); + + dest = gtk_drop_target_new (GDK_TYPE_PAINTABLE, GDK_ACTION_COPY); + g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL); + gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (dest)); + + gesture = gtk_gesture_click_new (); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY); + g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL); + gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (gesture)); +} + +static void +demo_image_dispose (GObject *object) +{ + DemoImage *demo = DEMO_IMAGE (object); + + g_clear_pointer (&demo->image, gtk_widget_unparent); + g_clear_pointer (&demo->popover, gtk_widget_unparent); + + G_OBJECT_CLASS (demo_image_parent_class)->dispose (object); +} + +static void +demo_image_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + DemoImage *demo = DEMO_IMAGE (object); + + switch (prop_id) + { + case PROP_ICON_NAME: + g_value_set_string (value, gtk_image_get_icon_name (GTK_IMAGE (demo->image))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +demo_image_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + DemoImage *demo = DEMO_IMAGE (object); + + switch (prop_id) + { + case PROP_ICON_NAME: + gtk_image_set_from_icon_name (GTK_IMAGE (demo->image), + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +demo_image_class_init (DemoImageClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->dispose = demo_image_dispose; + object_class->get_property = demo_image_get_property; + object_class->set_property = demo_image_set_property; + + g_object_class_install_property (object_class, PROP_ICON_NAME, + g_param_spec_string ("icon-name", "Icon name", "Icon name", + NULL, G_PARAM_READWRITE)); + + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); + + gtk_widget_class_install_action (widget_class, "clipboard.copy", NULL, copy_image); + gtk_widget_class_install_action (widget_class, "clipboard.paste", NULL, paste_image); +} + +GtkWidget * +demo_image_new (const char *icon_name) +{ + return g_object_new (DEMO_TYPE_IMAGE, "icon-name", icon_name, NULL); +} diff --git a/demos/gtk-demo/demoimage.h b/demos/gtk-demo/demoimage.h new file mode 100644 index 0000000000..bd8e160a73 --- /dev/null +++ b/demos/gtk-demo/demoimage.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +G_BEGIN_DECLS + +#define DEMO_TYPE_IMAGE (demo_image_get_type ()) + +G_DECLARE_FINAL_TYPE(DemoImage, demo_image, DEMO, IMAGE, GtkWidget) + +GtkWidget * demo_image_new (const char *icon_name); + +G_END_DECLS diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index 8a4ad34d6e..a2750049b7 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -90,6 +90,7 @@ extra_demo_sources = files(['main.c', 'gtkgears.c', 'puzzlepiece.c', 'bluroverlay.c', + 'demoimage.c', 'demotaggedentry.c']) if harfbuzz_dep.found() and pangoft_dep.found() -- 2.30.2